/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sessionBeans;

import entityBeans.SubjectEntity;
import java.util.ArrayList;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import utilities.HashFunctions;

/**
 *
 * @author h08125
 */
@Stateless
public class SubjectSessionBean implements SubjectSessionBeanLocal {
    @PersistenceContext(unitName="forum-ejbPU")
    protected EntityManager em;
    @Override
    public SubjectEntity getTopLevelSubject() {
        Query q = em.createNamedQuery("subject.topLevelSubject");
        return (q.getResultList().size() > 0) ? (SubjectEntity) q.getResultList().get(0) : null;
    }
    @Override
    public SubjectEntity getSubjectByUuid(String myUuid) {
        Query q = em.createNamedQuery("subject.subjectByUuid").setParameter("myUuid",myUuid);
        return (q.getResultList().size() > 0) ? (SubjectEntity) q.getResultList().get(0) : null;
    }
    @Override
    public SubjectEntity getSubjectById(int myId) {
        Query q = em.createNamedQuery("subject.subjectById").setParameter("myId",myId);
        return (q.getResultList().size() > 0) ? (SubjectEntity) q.getResultList().get(0) : null;
    }
    @Override
    public boolean addSubject(SubjectEntity myFatherSubject,SubjectEntity mySonSubject) {
        if (myFatherSubject != null) { // if the subject has a father
            mySonSubject.setMyFather(myFatherSubject);
            mySonSubject.setDepthLayer(mySonSubject.computeDepthLayer()); // compute the depthLayer
            em.persist(mySonSubject); // add subject in database
            myFatherSubject.getMySons().add(mySonSubject);
            em.merge(myFatherSubject);
        }
        else {
            if (mySonSubject.getMyFather() != null && !mySonSubject.getMyFather().getUuid().isEmpty()) { // if no uuid in the father
                // we extract the entire father
                mySonSubject.showValues();
                SubjectEntity newFather = this.getSubjectByUuid(mySonSubject.getMyFather().getUuid());
                newFather.showValues();
                if (this.isLegitimateFather(newFather,mySonSubject)) {
                    System.out.println("test");
                    mySonSubject.setMyFather(newFather);
                    mySonSubject.setDepthLayer(mySonSubject.computeDepthLayer()); // compute the depthLayer
                    em.persist(mySonSubject); // add subject in database
                    newFather.getMySons().add(mySonSubject);
                    em.merge(newFather);
                }
                else {
                    System.out.println("test2");
                    return false;
                }
            }
            else {
                em.persist(mySonSubject); // add subject in database
            }
        }
        mySonSubject.setUuid(HashFunctions.stringToSHA1(mySonSubject.getId().toString())); // hash the ID to create the UUID
        return true;
    }
    @Override
    public void modifySubject(SubjectEntity mySubject) {
        // we get the entire old father
        SubjectEntity oldFather = this.getSubjectById((int)(long)mySubject.getMyFather().getId());
        // we get the entire new father
        SubjectEntity newFather = this.getSubjectByUuid(mySubject.getMyFather().getUuid());
        
        // first, we need to check if this modification is legitimate. (if allowed father)
        if (this.isLegitimateFather(newFather,mySubject)) {
            // remove the son from the previous father (the id is from the previous father)
            oldFather.getMySons().remove(mySubject);

            // add the father to the son (The uuid is from the new father)
            mySubject.setMyFather(newFather);

            // we need to add the son to the father now (the father is now the right new father)
            newFather.getMySons().add(mySubject);

            // update the depthLayer, it may have changed
            mySubject.setDepthLayer(mySubject.computeDepthLayer());

            // update the database
            em.merge(mySubject);
            em.merge(oldFather);
            em.merge(newFather);
        }
    }
    @Override
    public ArrayList<SubjectEntity> getAdminRecursiveOrder(SubjectEntity mySubject,ArrayList<SubjectEntity> mySubjectList) {
        mySubjectList.add(mySubject);
        for (int i = 0; i < mySubject.getMySons().size(); i++) {
            mySubjectList = getAdminRecursiveOrder(mySubject.getMySons().get(i),mySubjectList);
        }
        return mySubjectList;
    }
    /**
     * Test if the father exists.
     * if it doesn't, there mustn't exist any subject in the DB.
     * The father can't have any thread.
     * the father can't be the subject itself.
     * @param father
     * @param son
     * @return true if the father is a legitimate father
     */
    private boolean isLegitimateFather(SubjectEntity father, SubjectEntity son) {
        if (father == null) {
            return (this.getTopLevelSubject() == null) ? true : false;
        }
        if (!father.getMyThreads().isEmpty()) { // no thread
            return false;
        }
        if (father.getId() == son.getId()) { // father and son are the same subject
            return false;
        }
        return true;
    }
    
}
